package com.aipanda.entity;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.Valid;
import javax.validation.constraints.Digits;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;

import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;

import com.fasterxml.jackson.annotation.JsonProperty;

/**
 * 促销类型类
 * @param 	name				促销名称
 * @param	title				标题
 * @param	beginDate			起始时间
 * @param	endDate				结束时间
 * @param	startPrice			起始商品价格
 * @param	endPrice			结束商品价格
 * @param	priceOperator		价格操作[加减乘除]
 * @param	priceValue			价格值[对应的加减乘除数]
 * @param	pointOperator		积分操作
 * @param	pointValue			积分值
 * @param	isFreeShipping		是否免运费
 * @param	isCouponAllowed		是否允许使用优惠券 
 * @param	introduction		介绍
 * @param	memberRanks			允许参加会员等级[多对多关系]
 * @param	productCategories	允许参与商品分类[多对多关系]
 * @param	products			允许参与产品[多对多关系]
 * @param	brands				允许参与品牌 [多对多关系]
 * @param 	coupons				赠送优惠券类型[多对多关系]
 * @param	giftItems			赠品[一对多关系]
 * @author wanyuxiang
 *
 */
@Entity
@Table(name = "aipanda_promotion")
public class Promotion extends OrderEntity {
	private static final long serialVersionUID = 3536993535267962279L;
	private String name;
	private String title;
	private Date beginDate;
	private Date endDate;
	private BigDecimal startPrice;
	private BigDecimal endPrice;
	private Operator priceOperator;
	private BigDecimal priceValue;
	private Operator pointOperator;
	private BigDecimal pointValue;
	private Boolean isFreeShipping;
	private Boolean isCouponAllowed;
	private String introduction;
	private Set<MemberRank> memberRanks = new HashSet<MemberRank>();
	private Set<ProductCategory> productCategories = new HashSet<ProductCategory>();
	private Set<Product> products = new HashSet<Product>();
	private Set<Brand> brands = new HashSet<Brand>();
	private Set<Coupon> coupons = new HashSet<Coupon>();
	private List<GiftItem> giftItems = new ArrayList<GiftItem>();

	public enum Operator {
		add, subtract, multiply, divide;
	}

	@JsonProperty
	@NotEmpty
	@Length(max = 255)
	@Column(nullable = false)
	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@JsonProperty
	@NotEmpty
	@Length(max = 255)
	@Column(nullable = false)
	public String getTitle() {
		return this.title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	@JsonProperty
	@Column(name="begin_date")
	public Date getBeginDate() {
		return this.beginDate;
	}

	public void setBeginDate(Date beginDate) {
		this.beginDate = beginDate;
	}

	@JsonProperty
	@Column(name="end_date")
	public Date getEndDate() {
		return this.endDate;
	}

	public void setEndDate(Date endDate) {
		this.endDate = endDate;
	}

	@JsonProperty
	@Min(0L)
	@Digits(integer = 15, fraction = 6)
	@Column(name="start_price",precision = 21, scale = 6)
	public BigDecimal getStartPrice() {
		return this.startPrice;
	}

	public void setStartPrice(BigDecimal startPrice) {
		this.startPrice = startPrice;
	}

	@JsonProperty
	@Min(0L)
	@Digits(integer = 15, fraction = 6)
	@Column(name="end_price",precision = 21, scale = 6)
	public BigDecimal getEndPrice() {
		return this.endPrice;
	}

	public void setEndPrice(BigDecimal endPrice) {
		this.endPrice = endPrice;
	}

	@NotNull
	@Column(name="price_operator",nullable = false)
	public Operator getPriceOperator() {
		return this.priceOperator;
	}

	public void setPriceOperator(Operator priceOperator) {
		this.priceOperator = priceOperator;
	}

	@Digits(integer = 15, fraction = 6)
	@Column(name="price_value",precision = 21, scale = 6)
	public BigDecimal getPriceValue() {
		return this.priceValue;
	}

	public void setPriceValue(BigDecimal priceValue) {
		this.priceValue = priceValue;
	}

	@NotNull
	@Column(name="point_operator",nullable = false)
	public Operator getPointOperator() {
		return this.pointOperator;
	}

	public void setPointOperator(Operator pointOperator) {
		this.pointOperator = pointOperator;
	}
	@Column(name="point_value")
	public BigDecimal getPointValue() {
		return this.pointValue;
	}

	public void setPointValue(BigDecimal pointValue) {
		this.pointValue = pointValue;
	}

	@NotNull
	@Column(name="is_free_shipping",nullable = false)
	public Boolean getIsFreeShipping() {
		return this.isFreeShipping;
	}

	public void setIsFreeShipping(Boolean isFreeShipping) {
		this.isFreeShipping = isFreeShipping;
	}

	@JsonProperty
	@NotNull
	@Column(name="is_coupon_allowed",nullable = false)
	public Boolean getIsCouponAllowed() {
		return this.isCouponAllowed;
	}

	public void setIsCouponAllowed(Boolean isCouponAllowed) {
		this.isCouponAllowed = isCouponAllowed;
	}

	@Lob
	public String getIntroduction() {
		return this.introduction;
	}

	public void setIntroduction(String introduction) {
		this.introduction = introduction;
	}

	@ManyToMany(fetch = FetchType.LAZY)
	@JoinTable(name = "aipanda_promotion_member_rank",joinColumns ={@JoinColumn(name="promotions",nullable=false)},inverseJoinColumns = {@JoinColumn(name="member_ranks",nullable=false)})
	public Set<MemberRank> getMemberRanks() {
		return this.memberRanks;
	}

	public void setMemberRanks(Set<MemberRank> memberRanks) {
		this.memberRanks = memberRanks;
	}

	@ManyToMany(fetch = FetchType.LAZY)
	@JoinTable(name = "aipanda_promotion_product_category",joinColumns ={@JoinColumn(name="promotions")},inverseJoinColumns = {@JoinColumn(name="product_categories")})
	public Set<ProductCategory> getProductCategories() {
		return this.productCategories;
	}

	public void setProductCategories(Set<ProductCategory> productCategories) {
		this.productCategories = productCategories;
	}

	@ManyToMany(fetch = FetchType.LAZY)
	@JoinTable(name = "aipanda_promotion_product",joinColumns ={@JoinColumn(name="promotions")},inverseJoinColumns = {@JoinColumn(name="products")})
	public Set<Product> getProducts() {
		return this.products;
	}

	public void setProducts(Set<Product> products) {
		this.products = products;
	}

	@ManyToMany(fetch = FetchType.LAZY)
	@JoinTable(name = "aipanda_promotion_brand",joinColumns ={@JoinColumn(name="promotions")},inverseJoinColumns = {@JoinColumn(name="brands")})
	public Set<Brand> getBrands() {
		return this.brands;
	}

	public void setBrands(Set<Brand> brands) {
		this.brands = brands;
	}

	@ManyToMany(fetch = FetchType.LAZY)
	@JoinTable(name = "aipanda_promotion_coupon",joinColumns ={@JoinColumn(name="promotions")},inverseJoinColumns = {@JoinColumn(name="coupons")})
	public Set<Coupon> getCoupons() {
		return this.coupons;
	}

	public void setCoupons(Set<Coupon> coupons) {
		this.coupons = coupons;
	}

	@Valid
	@OneToMany(mappedBy = "promotion", fetch = FetchType.LAZY, cascade = { CascadeType.ALL }, orphanRemoval = true)
	public List<GiftItem> getGiftItems() {
		return this.giftItems;
	}

	public void setGiftItems(List<GiftItem> giftItems) {
		this.giftItems = giftItems;
	}

	/**
	 * 是否是促销活动开始时间后
	 * @return
	 */
	@Transient
	public boolean hasBegun() {
		return (getBeginDate() == null) || (new Date().after(getBeginDate()));
	}

	/**
	 * 是否是促销活动结束时间后
	 * @return
	 */
	@Transient
	public boolean hasEnded() {
		return (getEndDate() != null) && (new Date().after(getEndDate()));
	}

	@Transient
	public String getPath() {
		if (getId() != null){
			return "/promotion/content/" + getId() + ".jhtml";
		}
		return null;
	}

	/**
	 * 计算促销后产品总金额
	 * @param totalAmount
	 * @return
	 */
	@Transient
	public BigDecimal calculatePromotionAfterAmount(BigDecimal totalAmount) {
		if ((totalAmount != null) && (getPriceOperator() != null)&& (getPriceValue() != null)) {
			BigDecimal actualAmount = new BigDecimal(0);
			if (getPriceOperator() == Operator.add){
				actualAmount = totalAmount.add(getPriceValue());
			}else if (getPriceOperator() == Operator.subtract){
				actualAmount = totalAmount.subtract(getPriceValue());
			}else if (getPriceOperator() == Operator.multiply){
				actualAmount = totalAmount.multiply(getPriceValue());
			}else{
				actualAmount = totalAmount.divide(getPriceValue());
			}
			return actualAmount.compareTo(new BigDecimal(0)) > 0 ? actualAmount: new BigDecimal(0);
		}
		return totalAmount;
	}

	/**
	 * 计算促销后积分值
	 * @param totalAmount   总积分
	 * @return  促销后的积分数
	 */
	@Transient
	public Integer calculatePromotionAfterPoint(Integer totalPoint) {
		if ((totalPoint != null) && (getPointOperator() != null)&& (getPointValue() != null)) {
			BigDecimal bd = new BigDecimal(0);
			if (getPointOperator() == Operator.add){
				bd = new BigDecimal(totalPoint).add(getPointValue());
			}else if (getPointOperator() == Operator.subtract){
				bd = new BigDecimal(totalPoint).subtract(getPointValue());
			}else if (getPointOperator() == Operator.multiply){
				bd = new BigDecimal(totalPoint).multiply(getPointValue());
			}else{
				bd = new BigDecimal(totalPoint).divide(getPointValue());
			}
			return bd.compareTo(new BigDecimal(0)) > 0 ? bd.intValue(): 0;
		}
		return totalPoint;
	}
}
